<template>
  <div class="crud-container">
    <!-- 查询表单 -->
    <el-form :inline="true" :model="queryForm" class="crud-form-inline">
      <div class="form-items-container">
        <div
          v-for="(row, rowIndex) in queryFieldRows"
          :key="rowIndex"
          class="form-row"
        >
          <div
            v-for="field in row"
            :key="field.prop"
            class="form-item"
            :style="{ width: `calc(${100 / queryFieldsPerRow}% - 16px)` }"
          >
            <el-form-item :label="field.label" :label-width="labelWidth">
              <component
                :is="field.type"
                v-model="queryForm[field.prop]"
                v-bind="field.attrs"
              >
                <template v-if="field.attrs && field.attrs.options">
                  <el-option
                    v-for="option in field.attrs.options"
                    :key="option.value"
                    :label="option.label"
                    :value="option.value"
                  ></el-option>
                </template>
              </component>
            </el-form-item>
          </div>
          <div
            v-if="rowIndex === queryFieldRows.length - 1"
            class="form-buttons"
          >
            <el-form-item>
              <el-button
                v-for="button in formButtons"
                :key="button.label"
                :type="button.type"
                @click="handleButtonClick(button)"
              >
                <i :class="button.icon" v-if="button.icon"></i>
                {{ button.label }}
              </el-button>
              <el-button
                v-if="queryFields.length > 2 * queryFieldsPerRow - 1"
                type="text"
                @click="toggleExpand"
              >
                {{ isExpanded ? "收起" : "展开" }}
                <el-icon v-if="isExpanded"><ArrowUp /></el-icon>
                <el-icon v-else><ArrowDown /></el-icon>
              </el-button>
            </el-form-item>
          </div>
        </div>
      </div>
    </el-form>
    <!-- 数据表格 -->
    <div class="crud-table-container">
      <div class="extra-buttons">
        <el-button
          v-for="button in extraButtons"
          :key="button.label"
          :type="button.type || ''"
          @click="button.handler"
          :class="button.class || 'default'"
        >
          <i :class="button.icon" v-if="button.icon"></i>
          {{ button.label }}
        </el-button>
      </div>
      <div class="table-wrapper">
        <el-table
          :data="tableData"
          style="width: 100%;"
          :height="tableHeight"
          :max-height="tableMaxHeight"
          @selection-change="handleSelectionChange"
        >
          <el-table-column
            v-if="selectable"
            type="selection"
            width="55"
          ></el-table-column>
          <el-table-column
            v-for="column in columns"
            :key="column.prop"
            :prop="column.prop"
            :label="column.label"
            :width="column.width"
            :fixed="column.fixed || false"
          >
            <template #default="scope">
              <component
                :is="column.render ? column.render(scope.row) : 'span'"
                v-if="column.render"
              />
              <span v-else>{{ scope.row[column.prop] }}</span>
            </template>
          </el-table-column>
          <el-table-column
            v-if="actionButtons.length"
            :label="actionColumn.label"
            :width="actionColumn.width"
            :fixed="actionColumn.fixed || false"
          >
            <template #default="scope">
              <div v-for="button in actionButtons" :key="button.label">
                <div
                  v-if="button.show ? button.show(scope.row) : true"
                  :class="button.type === 'link' ? 'text' : button.type"
                  @click="button.handler(scope.row)"
                  class="custom-link-button"
                >
                  <i :class="button.icon" v-if="button.icon"></i>
                  {{ button.label }}
                </div>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <CustomPagination
        v-if="paginated"
        :totalItems="total"
        v-model:currentPage="currentPage"
        v-model:pageSize="pageSize"
        :sizes="[10, 20, 30, 40]"
        @page-change="handleCurrentChange"
        @size-change="handleSizeChange"
        class="table-pagination"
      />
    </div>
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  ref,
  computed,
  onMounted,
  watch,
  nextTick,
  PropType
} from "vue";
import { ElMessage } from "element-plus";
import { ArrowUp, ArrowDown } from "@element-plus/icons-vue";
import debounce from "lodash/debounce";
import CustomPagination from "@/components/CustomPagination.vue";

interface QueryField {
  prop: string;
  label: string;
  type: string;
  defaultValue?: any;
  attrs?: {
    options?: { label: string; value: string | number }[];
    [key: string]: any;
  };
}

interface TableColumn {
  prop: string;
  label: string;
  width?: string;
  fixed?: boolean;
  render?: (row: any) => string | object;
}

interface FormButton {
  label: string;
  type?: string;
  icon?: string;
  handler: (form: Record<string, any>) => void;
}

interface ExtraButton {
  label: string;
  type?: string;
  icon?: string;
  class?: string;
  handler: () => void;
}

interface ActionButton {
  label: string;
  type?: string;
  icon?: string;
  show?: (row: any) => boolean;
  handler: (row: any) => void;
}

interface ActionColumn {
  label: string;
  width: string;
  fixed?: boolean;
}

export default defineComponent({
  name: "CrudComponent",
  components: { ArrowUp, ArrowDown, CustomPagination },
  props: {
    columns: { type: Array as PropType<TableColumn[]>, required: true },
    queryFields: { type: Array as PropType<QueryField[]>, default: () => [] },
    formButtons: { type: Array as PropType<FormButton[]>, default: () => [] },
    extraButtons: { type: Array as PropType<ExtraButton[]>, default: () => [] },
    actionButtons: {
      type: Array as PropType<ActionButton[]>,
      default: () => []
    },
    selectable: { type: Boolean, default: true },
    actionColumn: {
      type: Object as PropType<ActionColumn>,
      default: () => ({ label: "操作", width: "180" })
    },
    paginated: { type: Boolean, default: true },
    total: { type: Number, default: 0 },
    pageSize: { type: Number, default: 10 },
    queryFieldsPerRow: { type: Number, default: 3 },
    labelWidth: { type: String, default: "100px" },
    getListData: {
      type: Function as PropType<
        (params: any) => Promise<{ items: any[]; total: number }>
      >,
      required: true
    },
    parentHeight: { type: Number, default: window.innerHeight }
  },
  setup(props, { emit }) {
    const queryForm = ref<Record<string, any>>({});
    const tableData = ref<any[]>([]);
    const currentPage = ref(1);
    const pageSize = ref(props.pageSize);
    const total = ref(props.total);
    const tableHeight = ref(400);
    const tableMaxHeight = ref(500);
    const isExpanded = ref(false);

    const maxVisibleFields = computed(() => 2 * props.queryFieldsPerRow - 1);

    const visibleQueryFields = computed(() => {
      return isExpanded.value
        ? props.queryFields
        : props.queryFields.slice(0, maxVisibleFields.value);
    });

    const queryFieldRows = computed(() => {
      const rows = [];
      const perRow = props.queryFieldsPerRow;
      for (let i = 0; i < visibleQueryFields.value.length; i += perRow) {
        rows.push(visibleQueryFields.value.slice(i, i + perRow));
      }
      return rows;
    });

    const initializeQueryForm = () => {
      queryForm.value = props.queryFields.reduce((acc: any, field) => {
        acc[field.prop] = field.defaultValue || "";
        return acc;
      }, {});
    };

    const updateTableHeight = () => {
      nextTick(() => {
        const formHeight =
          document.querySelector(".crud-form-inline")?.clientHeight || 0;
        const extraButtonsHeight =
          document.querySelector(".extra-buttons")?.clientHeight || 0;
        const paginationHeight =
          document.querySelector(".table-pagination")?.clientHeight || 0;
        const availableHeight =
          props.parentHeight -
          formHeight -
          extraButtonsHeight -
          paginationHeight -
          160;
        tableHeight.value = availableHeight;
        tableMaxHeight.value = availableHeight;
      });
    };

    const loadData = debounce(async () => {
      try {
        const { items, total: totalCount } = await props.getListData({
          ...queryForm.value,
          page: currentPage.value,
          pageSize: pageSize.value
        });
        tableData.value = items;
        total.value = totalCount;
      } catch (error) {
        ElMessage.error("获取数据失败");
        console.error("数据加载错误:", error);
      }
    }, 300);

    const toggleExpand = () => {
      isExpanded.value = !isExpanded.value;
      nextTick(updateTableHeight);
    };

    const refreshTable = () => {
      loadData();
    };

    const handleButtonClick = (button: FormButton) => {
      button.handler(queryForm.value);
      refreshTable();
    };

    const handleSizeChange = (newSize: number) => {
      pageSize.value = newSize;
      refreshTable();
    };

    const handleCurrentChange = (newPage: number) => {
      currentPage.value = newPage;
      refreshTable();
    };

    const handleSelectionChange = (selection: any[]) => {
      emit("selection-change", selection);
    };

    onMounted(() => {
      initializeQueryForm();
      loadData();
      nextTick(() => {
        updateTableHeight();
      });
    });

    watch(() => props.queryFields, initializeQueryForm, {
      deep: true,
      immediate: true
    });
    watch([currentPage, pageSize, queryForm], loadData);
    watch(() => props.parentHeight, updateTableHeight);
    window.addEventListener("resize", updateTableHeight);

    return {
      queryForm,
      tableData,
      currentPage,
      pageSize,
      total,
      isExpanded,
      visibleQueryFields,
      queryFieldRows,
      toggleExpand,
      handleSizeChange,
      handleCurrentChange,
      tableHeight,
      tableMaxHeight,
      refreshTable,
      handleSelectionChange,
      handleButtonClick
    };
  }
});
</script>

<style scoped>
.crud-container {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 16px;
  height: 100%;
}
.crud-form-inline {
  width: 100%;
  border-radius: 4px;
  background: #fff;
  padding: 16px;
  padding-bottom: 0;
  align-items: center;
  color: #2d313b;
  font-family: Microsoft YaHei;
  font-size: 14px;
  font-weight: 400;
  line-height: 18.62px;
  text-align: left;
  border: 1px solid #ebecf0;
}
.form-items-container {
  display: flex;
  flex-direction: column;
  width: 100%;
}
.form-row {
  display: flex;
  gap: 16px;
  width: 100%;
  justify-content: flex-start;
}
.form-buttons {
  width: 200px;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  flex: 1 1 auto;
}
.extra-buttons {
  width: 100%;
  padding: 16px;
  padding-left: 0;
  padding-top: 0;
  padding-right: 0;
  border-radius: 4px;
  display: flex;
  justify-content: flex-start;
}
.crud-table-container {
  flex: 1;
  width: 100%;
  border-radius: 4px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.table-wrapper {
  flex: 1;
  overflow-x: auto;
}
.el-table {
  flex: 1;
  overflow: auto;
  min-width: 100%;
}
.table-pagination {
  display: flex;
}
.el-form-item__label {
  color: #333;
}
.custom-link-button {
  background: none;
  border: none;
  color: #409eff;
  cursor: pointer;
  margin-left: 10px;
}
.custom-link-button:not(:first-child) {
  margin-left: 10px;
}
.custom-link-button:hover {
  color: #66b1ff;
}
.el-table .el-table__fixed,
.el-table .el-table__fixed-right,
.el-table .el-table__fixed-header-wrapper {
  z-index: 101;
  background-color: #fff;
}
.el-table th,
.el-table td {
  white-space: nowrap;
  background: #fff;
}
.el-table .el-table__row--hover {
  background-color: #f5f7fa !important;
}
.el-table .el-table__fixed-body-wrapper .el-table__row--hover {
  background-color: #f5f7fa !important;
}
.el-table__fixed .el-table__fixed-body-wrapper {
  background-color: #fff;
}
.el-table__fixed-right .el-table__fixed-body-wrapper {
  background-color: #fff;
}
.el-table__fixed .el-table__fixed-body-wrapper .el-table__row {
  background-color: #fff !important;
  z-index: 102;
}
</style>
